package com.icinfo.cloud.provider.common.utils;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

/**
 * irs sign工具类
 *
 * @author Junfeng.Chen
 * @date 2023/12/21 11:25
 **/
public class IrsSignUtil {

    public static String getSign(String appSecret, Map<String, Object> param) throws Exception {
        String formattedString = formatSignatureParam(appSecret, param);
        return getMD5String(formattedString);
    }

    /**
     * 验证签名是否有效
     *
     * @param appSecret secret
     * @param param     参数map，包括header，query和body中的参数
     * @param sign      签名
     * @return
     */
    public static Boolean checkSignature(String appSecret, Map<String, Object> param, String sign) {
        String formattedString = formatSignatureParam(appSecret, param);
        return sign.equals(getMD5String(formattedString));
    }

    /**
     * @param secret app secret
     * @param param  参数map，包括header，query和body中的参数
     * @return
     */
    private static String formatSignatureParam(String secret, Map<String, Object> param) {
        if (param == null) {
            throw new RuntimeException("error param");
        }
        //使用TreeMap可以自动按照key字典顺序排序
        TreeMap<String, String> paramMap = new TreeMap<>();
        for (Map.Entry<String, Object> en : param.entrySet()) {
            if (null == en.getValue()) {
                continue;
            }
            //参数应当均为基本类型
            paramMap.put(en.getKey(), en.getValue().toString());
        }
        Set<Map.Entry<String, String>> entries = paramMap.entrySet();
        StringBuilder builder = new StringBuilder();
        for (Map.Entry<String, String> entry : entries) {
            String key = entry.getKey();
            String val = entry.getValue();
            builder.append(key)
                    .append("=")
                    .append(val)
                    .append("&");
        }
        return builder.append(secret).toString();
    }


    public static String getMD5String(String str) {
        byte[] bytes = null;
        try {
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            bytes = md5.digest(str.getBytes("UTF-8"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return bytes2Hex(bytes);
    }

    private static final char[] DIGITS_LOWER = {'0', '1', '2', '3', '4', '5',
            '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
    private static final char[] DIGITS_UPPER = {'0', '1', '2', '3', '4', '5',
            '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};

    public static String bytes2Hex(final byte[] data) {
        return bytes2Hex(data, true);
    }

    public static String bytes2Hex(final byte[] data, final boolean toLowerCase) {
        return bytes2Hex(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
    }

    private static String bytes2Hex(final byte[] data, final char[] toDigits) {
        final int l = data.length;
        final char[] out = new char[l << 1];
        // two characters form the hex value.
        for (int i = 0, j = 0; i < l; i++) {
            out[j++] = toDigits[(0xF0 & data[i]) >>> 4];
            out[j++] = toDigits[0x0F & data[i]];
        }
        return new String(out);
    }
}
